#pragma once
#include <fstream>
#include <sstream>

#include <string>
#include <iostream>
#include <vector>
#include <unordered_map>

#include "uncopyable.hpp"

const static std::string com_sep = "\r\n";
const static std::string req_sep = ": ";
const static std::string prefixpath = "wwwroot"; // web根目录
const static std::string homepage = "index.html";
const static std::string httpversion = "HTTP/1.0";
const static std::string spacesep = " ";
const static std::string html_404 = "404.html";
const static std::string suffixsep = ".";

class HttpRequest // 根据Http请求的结构确定
{
private:
    /// @brief 获得正文内容之前的信息
    /// @param reqstr
    /// @return 当前调用获取的一行字符串
    std::string Getline(std::string &reqstr)
    {
        auto pos = reqstr.find(com_sep);
        if (pos == std::string::npos)
            return std::string();

        std::string line = reqstr.substr(0, pos);      // 如果找到空行，则pos==0，截取出来的line是一个空串
        reqstr.erase(0, line.size() + com_sep.size()); // 若是，同样删掉空串
        if (line.empty())
            return com_sep; // 以这种方式返回，表示已经读取到空行

        return line;
    }
    void PraseReqLine()
    {
        // 创建一个字符串流，类似于cin，可以以空格为分隔符分别输入给多个变量
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _verson;

        // 构建真正的资源路径
        _path += _url;

        if (_path[_path.size() - 1] == '/')
        {
            _path += homepage;
        }
        auto pos = _path.rfind(suffixsep);
        if (pos != std::string::npos)
        {
            _suffix = _path.substr(pos);
        }
        else
        {
            _suffix = ".default";
        }
    }
    void PraseReqHeader()
    {
        for (auto &header : _req_headers)
        {
            auto pos = header.find(req_sep);
            if (pos == std::string::npos)
                continue;
            std::string k = header.substr(0, pos);
            std::string v = header.substr(pos + req_sep.size());
            if (k.empty() || v.empty())
                continue;
            _headers_kv.insert(std::make_pair(k, v));
        }
    }

public:
    HttpRequest()
        : _blank_line(com_sep), _path(prefixpath)
    {
    }
    std::string Suffix()
    {
        return _suffix;
    }
    /// @brief 序列化，解析http的请求内容
    /// @param reqstr 请求以字符串形式发送
    void Deserialize(std::string &reqstr)
    {
        // 基础反序列化
        _req_line = Getline(reqstr); // 获取请求行
        std::string header;
        while (true)
        {
            header = Getline(reqstr);
            if (header.empty())
                break;
            if (header == com_sep)
                break;

            _req_headers.push_back(header);
        }
        // 到这里，请求行和报头，空行被获取完
        if (!reqstr.empty())
            _body_text = reqstr;

        // 进一步反序列化(填写属性字段)

        PraseReqLine();
        PraseReqHeader();
    }

    void Print()
    {
        std::cout << "请求行:" << _req_line << std::endl;

        for (auto &header : _req_headers)
        {
            std::cout << "报头:" << header << std::endl;
        }
        std::cout << "空行:" << _blank_line;
        std::cout << "正文:" << _body_text << std::endl;

        std::cout << "method:" << _method << std::endl;
        std::cout << "url:" << _url << std::endl;
        std::cout << "verson:" << _verson << std::endl;

        for (auto header : _headers_kv)
        {
            std::cout << header.first << " " << header.second << std::endl;
        }
    }
    std::string GetUrl()
    {
        LOG(DEBUG, "client want url %s\n", _url.c_str());
        return _url;
    }
    std::string GetPath()
    {
        LOG(DEBUG, "client want path %s\n", _path.c_str());
        return _path;
    }

private:
    // 基本的httprequest的格式
    std::string _req_line; // 请求行
    std::vector<std::string> _req_headers;
    std::string _blank_line;
    std::string _body_text;

    std::string _suffix; // 资源后缀

    // 更具体的属性字段，需要进一步反序列化
    std::string _method;
    std::string _url;

    std::string _path; // 用户请求的资源的真实路径，路径前需要拼上wwwroot

    std::string _verson;
    std::unordered_map<std::string, std::string> _headers_kv; // 存储属性字段KV结构
};

class HttpReponse // 根据Http的响应的结构确定
{
public:
    HttpReponse() : _version(httpversion), _blank_line(com_sep)
    {
    }
    void AddCode(int code, const std::string &des)
    {
        _status_code = code;
        _desc = des;
    }
    void AddHeader(const std::string &k, const std::string &v)
    {
        _headers_kv[k] = v;
    }
    void AddBodyText(const std::string &body_text)
    {
        _resp_body_text = body_text;
    }
    std::string Serialize()
    {
        // 构建状态行
        _status_line = _version + spacesep + std::to_string(_status_code) + spacesep + _desc + com_sep;
        // 构建应答报头
        for (auto &header : _headers_kv)
        {
            std::string header_line = header.first + req_sep + header.second + com_sep;
            _resp_headers.push_back(header_line);
        }
        // 空行和正文

        // 正式序列化---构建http应答报文
        std::string responsestr = _status_line;
        for (auto &line_kv : _resp_headers)
        {
            responsestr += line_kv;
        }
        responsestr += _blank_line;
        responsestr += _resp_body_text;

        return responsestr;
    }
    ~HttpReponse()
    {
    }

private:
    // httpresponse base属性
    std::string _version;                                     // 版本
    int _status_code;                                         // 状态码
    std::string _desc;                                        // 状态描述
    std::unordered_map<std::string, std::string> _headers_kv; // 属性KV

    // http报文格式
    std::string _status_line;
    std::vector<std::string> _resp_headers;
    std::string _blank_line;
    std::string _resp_body_text;
};

class HttpServer : public uncopyable
{
private:
    // 获取文件内容
    std::string GetFileContent(const std::string &path)
    {
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return std::string();

        // 通过获得偏移量的方法计算文件大小
        in.seekg(0, in.end);
        int f_size = in.tellg();
        in.seekg(0, in.beg);

        std::string content;
        content.resize(f_size);
        in.read((char *)content.c_str(), f_size);
        in.close();

        return content;
    }

    // 添加可识别的文本类型
    void LoadContentType()
    {
        _my_type[".html"] = "text/html";
        _my_type[".jpg"] = "image/jpeg";
        _my_type[".png"] = "image/png";
        _my_type[".default"] = "text/html";
    }

    // 加载状态码到状态码描述的对应关系
    void LoadCodeToDesc()
    {
        _statuscode_to_desc[100] = "Continue";
        _statuscode_to_desc[200] = "OK";
        _statuscode_to_desc[201] = "Created";
        _statuscode_to_desc[301] = "Moved Permanently";//永久重定向
        _statuscode_to_desc[302] = "Found";//临时重定向
        _statuscode_to_desc[404] = "Not Found";
    }

public:
    HttpServer()
    {
        LoadContentType();
        LoadCodeToDesc();
    }
    std::string HanderHttpRequest(std::string &reqstr)
    {
#ifdef DEBUG
        std::cout << "---------------------------------------------" << std::endl;
        std::cout << reqstr;
        std::string responsestr = "HTTP/1.1 200 OK\r\n";
        responsestr += "Content-Type: text/html\r\n";
        responsestr += "\r\n";
        responsestr += "<html><h1>hello linux!</h1></html>";

        return responsestr;
#else
        HttpRequest req;
        req.Deserialize(reqstr);
        std::string content = GetFileContent(req.GetPath()); // 获取文件内容
        HttpReponse rsp;

        //重定向
        if (req.GetPath() == "wwwroot/redir")
        {
            //用新的地址替换旧的地址
            std::string redir_path = "https://www.baidu.com";
            rsp.AddCode(302,_statuscode_to_desc[302]);
            rsp.AddHeader("Location",redir_path);
        }
        else
        {
            if (content.empty())
            {
                // 读取失败，返回404.html
                content = GetFileContent("wwwroot/404.html");

                // 添加状态码
                rsp.AddCode(404,_statuscode_to_desc[404]);
                // 添加KV报头
                rsp.AddHeader("Content-Length", std::to_string(content.size()));
                rsp.AddHeader("Content-Type", _my_type[".html"]);

                // 添加正文
                rsp.AddBodyText(content);
            }
            else
            {
                // 添加状态码
                rsp.AddCode(200, _statuscode_to_desc[200]);

                // 添加KV报头
                rsp.AddHeader("Content-Length", std::to_string(content.size()));
                rsp.AddHeader("Content-Type", _my_type[req.Suffix()]);

                // 添加正文
                rsp.AddBodyText(content);
            }
        }

        return rsp.Serialize();
#endif
    }
    ~HttpServer() {}

private:
    // 可以识别的文本类型
    std::unordered_map<std::string, std::string> _my_type;
    // 添加状态码与状态码描述的对应关系
    std::unordered_map<int, std::string> _statuscode_to_desc;
};